#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <ThreeWire.h>  
#include <RtcDS1302.h>  //Rtc by Makuna
#include <FS.h> 

#include "DHTesp.h"
#include "sreen.h"
#include "status.h"
#include "setting.h"

//================ 宏定义 ================
//检测水杯IO
#define PinDetect 13

//温湿度传感器 dht11 IO    
#define PinDHT11 14     

//OLED屏幕IIC
//SDA D2 
//SCL D1

//DS1302时钟模块
#define DS1302_CLK 2 
#define DS1302_DAT 0
#define DS1302_RST 15

#define Ctl_Reboot  "reboot"
#define Ctl_Time "time"
#define Ctl_WifiConnState  "wifiConnState"

//================ 对象 ================
Ticker stateTimer;         //状态检测定时器
Ticker uiTimer;         //UI驱动定时器
DHTesp dht;
ThreeWire myWire(DS1302_DAT,DS1302_CLK,DS1302_RST); // IO, CLK, RST
RtcDS1302<ThreeWire> rtc(myWire);   

//================ 变量 ================
float dht_temp = -999; 
float dht_hum = -999; 

//================ 函数 ================
bool control(String key,String value);
void setCurrentTime(String valueTime);
void setWifiConnect(bool flag);

void updatePrint();
void updateUi();
void updateStatus();

void cmdPara(String cmdStr);
void commHandle();

void setup() 
{
  Serial.begin(115200);   
  pinMode(PinDetect, INPUT);
  sreen.init();     //ui界面初始化、比较耗时
  if(setting.init())   //配置模块初始化
  {
    setting.wifi_bootConn = 0;
    setting.wifi_ssid = "求取得密码！";
    setting.wifi_pwd = "jiangtao000!!!";

    setting.mqtt_bootConn = 1;
    setting.mqtt_addr = "1292.168.123.112";
    setting.mqtt_port = "18920";
    setting.mqtt_name = "mqttName";
    setting.mqtt_pwd = "mqtt_pwd000!!!";

    setting.log_outFlag = 0;

    bool res = setting.saveToFile();
    Serial.print("save res:");
    Serial.print(res);
    res = setting.readFromFile();
    Serial.println("Read res:");
    Serial.print(res);
    Serial.println("Read data:");
    
    Serial.println(setting.wifi_bootConn);
    Serial.println(setting.wifi_ssid);
    Serial.println(setting.wifi_pwd);

    Serial.println(setting.mqtt_bootConn);
    Serial.println(setting.mqtt_addr);
    Serial.println(setting.mqtt_port);
    Serial.println(setting.mqtt_name);
    Serial.println(setting.mqtt_pwd);

    Serial.println(setting.log_outFlag);

  }
  state.update(digitalRead(PinDetect));   //状态更新
  dht.setup(PinDHT11, DHTesp::DHT11);   //温湿度模块初始化
  rtc.Begin();    //时钟模块初始化
  //rtc.adjust(DateTime(__DATE__, __TIME__));
  //wifiConnect();
  stateTimer.attach_ms(100, updateStatus);    //状态检测定时器
  //uiTimer.attach_ms(100, updateUi);           //ui界面刷新定时器
  //ESP.deepSleep(2l ); // 20e6 is 20 microseconds
}

void loop()  
{
    delay(80);
    updateUi();
    if(Serial.available() > 0)
      commHandle();         //通信处理函数
}

//串口控制处理函数
bool control(String key,String value)
{
    if(key == Ctl_Reboot)
    {
      system_restart();
    }
    else if(key == Ctl_Time)    //时间设置特殊，不是变量控制
    {
        setCurrentTime(value);
    }
    else if(key == Ctl_WifiConnState)
    {
      //setWifiConnect(int(value.trim()));
    }
    else
      return 0;
    return 1;
}

//设置时间函数
void setCurrentTime(String valueTime)
{
  int pos = valueTime.indexOf(",");
  if(pos <= 0)
    return ;
  char dateStr[20] = "";
  char timeStr[20] = "";
  valueTime.substring(0,pos).toCharArray(dateStr,pos+1);
  valueTime.substring(pos+1).toCharArray(timeStr,valueTime.length()-pos);
  RtcDateTime compiled = RtcDateTime(dateStr, timeStr);
  rtc.SetDateTime(compiled);
}

//wifi连接函数、断开
void setWifiConnect(bool flag)
{
  if(flag)
  {
    //sreen.showWifiConnect(setting.wifi_ssid,setting.wifi_pwd);
    WiFi.begin(setting.wifi_ssid,setting.wifi_pwd);
    int wifiCount = 120;  //60s没有连接上就重启
    while (WiFi.status() != WL_CONNECTED) 
    {
      delay(500);
      wifiCount --;
      if(wifiCount <= 0)
      {
        break;    
        //system_restart();
      }
    }
  }
  else  //断开
  {
    
  }
}

//日志刷新函数
void updatePrint()
{
  static int countPrint = 0;
  if(countPrint++ < 10)
    return ;
  countPrint  = 0;
  Serial.print("Status：");
  switch(state.mType)
  {
    case Status::eDrinking:  Serial.print("drinking"); break;
    case Status::eWaitting:  Serial.print("waitting"); break;
    case Status::eOutTime_1: Serial.print("outtime_1"); break;
    case Status::eOutTime_2: Serial.print("outtime_2"); break;
    case Status::eOutTime_3: Serial.print("outtime_3"); break;
    case Status::eOutTime_4: Serial.print("outtime_4"); break;
    case Status::eOutTime_5: Serial.print("outtime_5"); break;
    default: Serial.print("unknown"); break;
  }
  Serial.print("   Time：");
  Serial.print(state.mSecTime);
  Serial.print(" s");   
  Serial.println("");   
}

//界面刷新函数
void updateUi()
{
    if((state.mSecTime % setting.ui_period) > (setting.ui_switch - 1))
    {
      static int countDTH11 = 10000;
      static int countTime = 10000;
      static float temp = 0.0;
      static float hum = 0.0;
      static RtcDateTime nowTime;
      //读取时间
      countTime ++;
      if(countTime > 10){
        if (!rtc.GetIsRunning())
        {
            Serial.println("RTC was not actively running, starting now");
            rtc.SetIsRunning(true);
        }
        countTime = 0;
        nowTime = rtc.GetDateTime();
      }
      
      //读取温度
      countDTH11 ++;
      if(countDTH11 > 50 ){
        countDTH11 = 0;
        TempAndHumidity dhtValues = dht.getTempAndHumidity();
        temp = dhtValues.temperature;
        hum = dhtValues.humidity;
      }
      //显示时间、温度湿度
      sreen.showTimeDHT11(temp,hum,&nowTime,state.mIsWarning);
      return ;
    }
    //刷新其他表情包界面
    switch(state.mType)
    {
        case Status::eDrinking:   sreen.updateDrinking(state.mSecTime);  break;
        case Status::eWaitting:   sreen.updateWaitting(state.mSecTime);  break;  
        case Status::eOutTime_1:  sreen.updateOutTime_1(state.mSecTime);  break;
        case Status::eOutTime_2:  sreen.updateOutTime_2(state.mSecTime);  break;  
        case Status::eOutTime_3:  sreen.updateOutTime_3(state.mSecTime);  break; 
        case Status::eOutTime_4:  sreen.updateOutTime_4(state.mSecTime);  break;  
        case Status::eOutTime_5:  sreen.updateOutTime_5(state.mSecTime);  break; 
        case Status::eNull: 
        default:    break;    
    }
}

//状态检测更新函数 ，100ms驱动
void updateStatus()  
{
  //状态检测
  static bool lastState = 0;
  bool haveCup = digitalRead(PinDetect);   //检测杯子存在，1-有杯子，0-无杯子
  if(haveCup == lastState)
    state.advance();    //状态没有改动就延时变动
  else 
    state.update(haveCup);    //改动状态，复位时间
  lastState = haveCup;
  
  //updatePrint();        //打印信息
  //updateUi();
}

//串口命令处理函数
  //set - Key : Value   , return set Ok! Key:Value
  //get - Key          , return Key:Value
  //ctl - Key(opt):value      , type:reboot、connectWifi、disconnectWifi,最后的参数可有可无
void cmdPara(String cmdStr)
{
  cmdStr.trim();
  int cmdLen = cmdStr.length();       //获取读取数据长度
  int start_key = cmdStr.indexOf('-');   //获取key起始位置
  
  if(start_key == -1)
  {
    Serial.println("para Error! "+cmdStr);
    return ;
  }
  int posBuff = cmdStr.indexOf(':'); //获取value起始位置
  int start_value = start_value < 0 ? cmdLen: posBuff;   
  
  String keyStr = cmdStr.substring(start_key+1,start_value);
  keyStr.trim();

  if (cmdStr.startsWith("set"))   //=== 设置命令 === 
  {
      if(start_value < 0)  //解析错误，set模式无value
      {
          Serial.println("para Error! "+cmdStr);
          return ;
      }
      String valueStr = cmdStr.substring(start_value+1,cmdLen);
      valueStr.trim();
      bool res = setting.setValue(keyStr,valueStr);
      if(res)
          Serial.println("set Ok! " + keyStr + ":" + valueStr);
      else
          Serial.println("set Error! " + keyStr + ":" + valueStr);
  }   
  else if (cmdStr.startsWith("get"))  //=== 读取命令 === 
  {
      String valueStr = setting.getValue(keyStr);
      Serial.println("get Ok! " + keyStr + ":" + valueStr);
  }
  else if (cmdStr.startsWith("ctl"))  //=== 控制命令 === 
  {
      String valueStr = "";
      if(start_value > 0)  
      {
        valueStr = cmdStr.substring(start_value+1,cmdLen);
        valueStr.trim();
      }
      bool res = control(keyStr,valueStr); 
      if(res)
          Serial.println("ctl Ok! " + keyStr + ":" + valueStr);
      else
          Serial.println("ctl Error! " + keyStr + ":" + valueStr);
  }  
  else  //===  解析错误，命令字未识别 === 
      Serial.println("para Error! "+cmdStr);
}
//串口数据接收函数
void commHandle()
{
  String rxStr = Serial.readString();   //读取串口
  rxStr.trim();
  while(rxStr.length()>4)
  {
    int endPos = rxStr.indexOf(';');  //找个命令分割位置
    int cmdSplitePos = endPos < 0 ? rxStr.length(): endPos;
    String cmdStr = rxStr.substring(0,cmdSplitePos);  //获取最前面的命令
    cmdPara(cmdStr);  //解析命令
    rxStr.remove(0,cmdSplitePos + 1); //更新还未解析的命令
    rxStr.trim();
//    Serial.println("allCMD: "+rxStr);
  }
}
